#include "stdafx.h"
#include "teainifile.h"
#include <crypto/crypto.h>
using namespace crypto;

namespace Zen{ namespace utility{ namespace ini{

#define DELTA 0x9e3779b9 /* sqr(5)-1 * 2^31 */
const int g_key[4] = { 0x3256CDEB, 0x812FB863, 0xC52E550A, 0xDB555C85, };

void tean(int v[2], long N)
{
    int y = v[0], z = v[1];
    int limit,sum = 0;

    /* ENCRYPT */
    if (N > 0)
    {
        limit = DELTA * N;
        while (sum != limit)
        {
            y += ((z << 4) ^ (z >> 5)) + (z ^ sum) + g_key[sum & 3];
            sum += DELTA;
            z += ((y << 4) ^(y >> 5)) + (y ^ sum) + g_key[(sum >> 11) & 3];
        }
    }
    /* DECRYPT */
    else
    {
        sum = DELTA * (-N);
        while (sum)
        {
            z -= ((y << 4) ^ (y >> 5)) + (y ^ sum) + g_key[(sum >> 11) & 3];
            sum -= DELTA;
            y -= ((z << 4) ^ (z >> 5)) + (z ^ sum) + g_key[sum & 3];
        }
    }
    v[0] = y;
    v[1] = z;
}
    
TEAIniFile::TEAIniFile(int rounds/*=32*/)
    : rounds_(rounds)
{}

bool TEAIniFile::Encrypt(ostream& encrypted, istream& decrypted) const
{
    unsigned char buf[1024];
    size_t size = 0;
    while (size = decrypted.read((char*)buf, 1024).gcount())
    {
        if (size < 1024)
            memset(&buf[size], 0, 1024 - size);
        if ((size & 0x07) > 0)
            size = (size & 0xfffffff8) + 8;
        int *p = (int*)buf;
        for (int i = 0; i < int(size / 8); i++)
        {
            tean(p, rounds_);
            p += 2;
        }
        encrypted.write((const char*)buf, size);
    }
    return !encrypted.fail();
}

bool TEAIniFile::Decrypt(ostream& decrypted, istream& encrypted) const
{
    unsigned char buf[1024];
    size_t size = 0;
    while (size = encrypted.read((char*)buf, 1024).gcount())
    {
        int *p = (int*)buf;
        for (int i = 0; i < int(size / 8); i++)
        {
            tean(p, -rounds_);
            p += 2;
        }
        decrypted.write((const char*)buf, size);
    }
    return !decrypted.fail();
}

//////////////////////////////////////////////////////////////////////////

bool TEAIniFile2::Encrypt(ostream& encrypted, istream& decrypted) const
{
	string src, dst;
	char buf[1024] = {0};
	size_t size = 0;
	while (size = decrypted.read((char*)buf, 1024).gcount())
	{
		string tmp(buf, size);
		src.append(tmp);
	}

	tea_encrypt(src, dst);
	encrypted.write(dst.c_str(), dst.length());

	return !encrypted.fail();
}

bool TEAIniFile2::Decrypt(ostream& decrypted, istream& encrypted) const
{
	string src, dst;
	char buf[1024] = {0};
	size_t size = 0;
	while (size = encrypted.read((char*)buf, 1024).gcount())
	{
		string tmp(buf, size);
		src.append(tmp);
	}

	tea_dencrypt(src, dst);

	decrypted.write(dst.c_str(), dst.length());
	return !decrypted.fail();
}


}}}